2 * NDComponentInstance.m
3 * NDAppleScriptObjectProject
5 * Created by Nathan Day on Tue May 20 2003.
6 * Copyright (c) 2002 Nathan Day. All rights reserved.
9 #import "NDComponentInstance.h"
10 #import "NSAppleEventDescriptor+NDAppleScriptObject.h"
11 #include "NDProgrammerUtilities.h"
13 const OSType kFinderCreatorCode = 'MACS';
15 const NSString * NDAppleScriptOffendingObject = @"Error Offending Object",
16 * NDAppleScriptPartialResult = @"Error Partial Result";
19 * function AppleScriptActiveProc
21 static OSErr AppleScriptActiveProc( long aRefCon )
23 NDComponentInstance * self = (id)aRefCon;
24 id theActiveTarget = [self activeTarget];
25 OSErr theError = errOSASystemError;
27 NSCParameterAssert( self != nil );
29 if( theActiveTarget != nil )
30 theError = [theActiveTarget appleScriptActive] ? noErr : errOSASystemError;
32 theError = (self->defaultActiveProcPtr)( self->defaultActiveProcRefCon );
37 static OSErr AppleEventResumeHandler(const AppleEvent * anAppleEvent, AppleEvent * aReply, long aRefCon )
39 NDComponentInstance * self = (id)aRefCon;
40 OSErr theError = errAEEventNotHandled;
41 id <NDScriptDataAppleEventResumeHandler> theResumeHandler = [self appleEventResumeHandler];
42 NSAppleEventDescriptor * theResult = nil;
44 NSCParameterAssert( self != nil );
46 if( theResumeHandler == nil )
47 theResumeHandler = self;
49 theResult = [theResumeHandler handleResumeAppleEvent:[NSAppleEventDescriptor descriptorWithAEDesc:anAppleEvent]];
53 NSCParameterAssert( [theResult getAEDesc:aReply] );
57 theError = errOSASystemError;
63 * category interface NDComponentInstance (Private)
65 @interface NDComponentInstance (Private)
66 - (ComponentInstance)instanceRecord;
70 * class implementation NDComponentInstance
72 @implementation NDComponentInstance
74 static NDComponentInstance * sharedComponentInstance = nil;
77 * +sharedComponentInstance
79 + (id)sharedComponentInstance
81 if( sharedComponentInstance == nil )
82 sharedComponentInstance = [[self alloc] init];
83 NSAssert( sharedComponentInstance != nil, @"Could not create shared Component Instance" );
84 return sharedComponentInstance;
88 * +closeSharedComponentInstance
90 + (void)closeSharedComponentInstance
92 [sharedComponentInstance release];
93 sharedComponentInstance = nil;
99 + (Component)findNextComponent
101 ComponentDescription theReturnCompDesc;
102 static Component theLastComponent = NULL;
103 ComponentDescription theComponentDesc;
105 theComponentDesc.componentType = kOSAComponentType;
106 theComponentDesc.componentSubType = kOSAGenericScriptingComponentSubtype;
107 theComponentDesc.componentManufacturer = 0;
108 theComponentDesc.componentFlags = kOSASupportsCompiling | kOSASupportsGetSource | kOSASupportsAECoercion | kOSASupportsAESending | kOSASupportsConvenience | kOSASupportsDialects | kOSASupportsEventHandling;
110 theComponentDesc.componentFlagsMask = theComponentDesc.componentFlags;
114 theLastComponent = FindNextComponent( theLastComponent, &theComponentDesc );
116 while( GetComponentInfo( theLastComponent, &theReturnCompDesc, NULL, NULL, NULL ) == noErr && theComponentDesc.componentSubType == kOSAGenericScriptingComponentSubtype );
118 return theLastComponent;
122 * + componentInstance
124 + (id)componentInstance
126 return [[[self alloc] init] autorelease];
130 * +componentInstanceWithComponent:
132 + (id)componentInstanceWithComponent:(Component)aComponent
134 return [[[self alloc] initWithComponent:aComponent] autorelease];
142 return [self initWithComponent:NULL];
146 * -initWithComponent:
148 - (id)initWithComponent:(Component)aComponent
150 if( (self = [super init]) != nil )
152 if( aComponent == NULL )
155 if( (instanceRecord = OpenDefaultComponent( kOSAComponentType, kAppleScriptSubtype )) == NULL )
159 NSLog(@"Could not open connection with default AppleScript component");
162 else if( (instanceRecord = OpenComponent( aComponent )) == NULL )
166 NSLog(@"Could not open connection with component");
177 [self setAppleEventSendTarget:nil];
178 [self setActiveTarget:nil];
179 // [self setAppleEventSpecialHandler:nil];
180 [self setAppleEventResumeHandler:nil];
182 if( instanceRecord != NULL )
184 CloseComponent( instanceRecord );
190 * - setDefaultTarget:
192 - (void)setDefaultTarget:(NSAppleEventDescriptor *)aDefaultTarget
194 if( OSASetDefaultTarget( [self instanceRecord], [aDefaultTarget aeDesc] ) != noErr )
195 NSLog( @"Could not set default target" );
199 * - setDefaultTargetAsCreator:
201 - (void)setDefaultTargetAsCreator:(OSType)aCreator
203 NSAppleEventDescriptor * theAppleEventDescriptor;
205 theAppleEventDescriptor = [NSAppleEventDescriptor descriptorWithDescriptorType:typeApplSignature data:[NSData dataWithBytes:&aCreator length:sizeof(aCreator)]];
206 [self setDefaultTarget:theAppleEventDescriptor];
210 * - setFinderAsDefaultTarget
212 - (void)setFinderAsDefaultTarget
214 [self setDefaultTargetAsCreator:kFinderCreatorCode];
217 - (void)setAppleEventSendTarget:(id<NDScriptDataSendEvent>)aTarget
219 [self setAppleEventSendTarget:aTarget currentProcessOnly:NO];
223 * setAppleEventSendTarget:
225 - (void)setAppleEventSendTarget:(id<NDScriptDataSendEvent>)aTarget currentProcessOnly:(BOOL)aFlag;
227 sendAppleEvent.currentProcessOnly = aFlag;
228 if( aTarget != sendAppleEvent.target )
230 OSErr AppleEventSendProc( const AppleEvent *theAppleEvent, AppleEvent *reply, AESendMode sendMode, AESendPriority sendPriority, long timeOutInTicks, AEIdleUPP idleProc, AEFilterUPP filterProc, long refCon );
232 NSParameterAssert( sizeof(long) == sizeof(id) );
234 /* need to save the default send proceedure as we will call it in our send proceedure */
237 if( defaultSendProcPtr == NULL ) // need to save this so we can restor it
239 OSASendUPP theDefaultSendProcPtr;
240 long int theDefaultSendProcRefCon;
241 ComponentInstance theComponent = [self instanceRecord];
243 NSAssert( OSAGetSendProc( theComponent, &theDefaultSendProcPtr, &theDefaultSendProcRefCon) == noErr, @"Could not get default AppleScript send procedure");
246 * make sure we haven't already set the send procedure for this component instance.
248 if( theDefaultSendProcPtr != AppleEventSendProc )
250 defaultSendProcPtr = theDefaultSendProcPtr;
251 defaultSendProcRefCon = theDefaultSendProcRefCon;
253 else // get the original component instance
255 NSLog( @"The send procedure for this component instance is already set." );
256 defaultSendProcPtr = ((NDComponentInstance*)theDefaultSendProcRefCon)->defaultSendProcPtr;
257 defaultSendProcRefCon = ((NDComponentInstance*)theDefaultSendProcRefCon)->defaultSendProcRefCon;
259 NSAssert( OSASetSendProc( theComponent, AppleEventSendProc, (long)self ) == noErr, @"Could not set send procedure" );
262 [sendAppleEvent.target release];
263 sendAppleEvent.target = [aTarget retain];
267 [sendAppleEvent.target release];
268 sendAppleEvent.target = nil;
270 NSAssert( OSASetSendProc( [self instanceRecord], defaultSendProcPtr, defaultSendProcRefCon ) == noErr, @"Could not restore default send procedure");
272 defaultSendProcPtr = NULL;
273 defaultSendProcRefCon = 0;
279 * appleEventSendTarget
281 - (id<NDScriptDataSendEvent>)appleEventSendTarget
283 return sendAppleEvent.target;
286 - (BOOL)appleEventSendCurrentProcessOnly
288 return sendAppleEvent.currentProcessOnly;
294 - (void)setActiveTarget:(id<NDScriptDataActive>)aTarget
296 if( aTarget != activeTarget )
298 NSParameterAssert( sizeof(long) == sizeof(id) );
302 /* need to save the default active proceedure as we will call it in our active proceedure */
303 if( defaultActiveProcPtr == NULL )
305 ComponentInstance theComponent = [self instanceRecord];
307 NSAssert( OSAGetActiveProc(theComponent, &defaultActiveProcPtr, &defaultActiveProcRefCon ) == noErr, @"Could not get default AppleScript active procedure");
308 NSAssert( OSASetActiveProc( theComponent, AppleScriptActiveProc , (long)self ) == noErr, @"Could not set AppleScript active procedure.");
311 [activeTarget release];
312 activeTarget = [aTarget retain];
314 else if( defaultActiveProcPtr == NULL )
316 [activeTarget release];
318 NSAssert( OSASetActiveProc( [self instanceRecord], defaultActiveProcPtr, defaultActiveProcRefCon ) == noErr, @"Could not set default active procedure.");
319 defaultActiveProcPtr = NULL;
320 defaultActiveProcRefCon = 0;
328 - (id<NDScriptDataActive>)activeTarget
335 * -setAppleEventSpecialHandler:
337 - (void)setAppleEventSpecialHandler:(id<NDScriptDataAppleEventSpecialHandler>)aHandler
339 if( aHandler != appleEventSpecialHandler )
341 [appleEventSpecialHandler release];
342 appleEventSpecialHandler = [aHandler retain];
347 * -appleEventSpecialHandler
349 - (id<NDScriptDataAppleEventSpecialHandler>)appleEventSpecialHandler
351 return appleEventSpecialHandler;
356 * -setAppleEventResumeHandler:
358 - (void)setAppleEventResumeHandler:(id<NDScriptDataAppleEventResumeHandler>)aHandler
360 if( aHandler != appleEventResumeHandler )
362 if( defaultResumeProcPtr == NULL )
363 NDLogOSStatus( OSAGetResumeDispatchProc ( [self instanceRecord], &defaultResumeProcPtr, &defaultResumeProcRefCon ) );
365 NDLogOSStatus( OSASetResumeDispatchProc( [self instanceRecord], AppleEventResumeHandler, (long int)self ) );
366 [(NSObject *)appleEventResumeHandler release];
367 appleEventResumeHandler = [(NSObject *)aHandler retain];
372 * -appleEventResumeHandler
374 - (id<NDScriptDataAppleEventResumeHandler>)appleEventResumeHandler
376 return appleEventResumeHandler;
380 * -sendAppleEvent:sendMode:sendPriority:timeOutInTicks:idleProc:filterProc:
382 - (NSAppleEventDescriptor *)sendAppleEvent:(NSAppleEventDescriptor *)anAppleEventDescriptor sendMode:(AESendMode)aSendMode sendPriority:(AESendPriority)aSendPriority timeOutInTicks:(long)aTimeOutInTicks idleProc:(AEIdleUPP)anIdleProc filterProc:(AEFilterUPP)aFilterProc
384 NSAppleEventDescriptor * theReplyAppleEventDescriptor = nil;
385 AEDesc theReplyDesc = { typeNull, NULL };
387 NSParameterAssert( defaultSendProcPtr != NULL );
389 // if( NDLogOSStatus( defaultSendProcPtr( [anAppleEventDescriptor aeDesc], &theReplyDesc, aSendMode, aSendPriority, aTimeOutInTicks, anIdleProc, aFilterProc, defaultSendProcRefCon ) ) )
390 NDLogOSStatus( defaultSendProcPtr( [anAppleEventDescriptor aeDesc], &theReplyDesc, aSendMode, aSendPriority, aTimeOutInTicks, anIdleProc, aFilterProc, defaultSendProcRefCon ) );
392 theReplyAppleEventDescriptor = [NSAppleEventDescriptor descriptorWithAEDescNoCopy:&theReplyDesc];
395 return theReplyAppleEventDescriptor;
401 - (BOOL)appleScriptActive
403 NSParameterAssert( defaultActiveProcPtr != NULL );
404 return defaultActiveProcPtr( defaultActiveProcRefCon ) == noErr;
408 * -handleResumeAppleEvent:
410 - (NSAppleEventDescriptor *)handleResumeAppleEvent:(NSAppleEventDescriptor *)aDescriptor
412 AEDesc theReplyDesc = { typeNull, NULL };
413 return defaultResumeProcPtr([aDescriptor aeDesc], &theReplyDesc, defaultResumeProcRefCon ) == noErr ? [NSAppleEventDescriptor descriptorWithAEDescNoCopy:&theReplyDesc] : nil;
420 - (NSDictionary *)error
422 AEDesc theDescriptor = { typeNull, NULL };
423 unsigned int theIndex;
424 NSMutableDictionary * theDictionary = [NSMutableDictionary dictionaryWithCapacity:7];
426 struct { const NSString * key; const DescType desiredType; const OSType selector; }
428 { NSAppleScriptErrorMessage, typeText, kOSAErrorMessage },
429 { NSAppleScriptErrorNumber, typeShortInteger, kOSAErrorNumber },
430 { NSAppleScriptErrorAppName, typeText, kOSAErrorApp },
431 { NSAppleScriptErrorBriefMessage, typeText, kOSAErrorBriefMessage },
432 { NSAppleScriptErrorRange, typeOSAErrorRange, kOSAErrorRange },
433 { NDAppleScriptOffendingObject, typeObjectSpecifier, kOSAErrorOffendingObject, },
434 { NDAppleScriptPartialResult, typeBest, kOSAErrorPartialResult },
437 for( theIndex = 0; theResults[theIndex].key != nil; theIndex++ )
439 if( OSAScriptError([self instanceRecord], theResults[theIndex].selector, theResults[theIndex].desiredType, &theDescriptor ) == noErr )
441 [theDictionary setObject:(id)[[NSAppleEventDescriptor descriptorWithAEDescNoCopy:&theDescriptor] objectValue] forKey:(id)theResults[theIndex].key];
445 return theDictionary;
453 AEDesc theDesc = { typeNull, NULL };
454 NSString * theName = nil;
455 if ( OSAScriptingComponentName( [self instanceRecord], &theDesc) == noErr )
456 theName = [[NSAppleEventDescriptor descriptorWithAEDescNoCopy:&theDesc] stringValue];
464 - (NSString *)description
466 NSString * theName = [self name];
467 return theName == nil
468 ? [@"NDComponentInstance name:" stringByAppendingString:theName]
469 : @"NDComponentInstance name: not available";
473 * -isEqualToComponentInstance:
475 - (BOOL)isEqualToComponentInstance:(NDComponentInstance *)aComponentInstance
477 return aComponentInstance == self || [aComponentInstance instanceRecord] == [self instanceRecord];
483 - (BOOL)isEqualTo:(id)anObject
485 return anObject == self || ([anObject isKindOfClass:[self class]] && [self isEqualToComponentInstance:anObject]);
491 - (id)copyWithZone:(NSZone *)aZone
493 return [self retain];
501 return (unsigned int)instanceRecord;
505 * function AppleEventSendProc
507 OSErr AppleEventSendProc( const AppleEvent *anAppleEvent, AppleEvent *aReply, AESendMode aSendMode, AESendPriority aSendPriority, long aTimeOutInTicks, AEIdleUPP anIdleProc, AEFilterUPP aFilterProc, long aRefCon )
509 NDComponentInstance * self = (id)aRefCon;
510 OSErr theError = errOSASystemError;
511 id theSendTarget = [self appleEventSendTarget];
512 BOOL theCurrentProcessOnly = [self appleEventSendCurrentProcessOnly];
513 NSAppleEventDescriptor * theAppleEventDescReply,
514 * theAppleEventDescriptor = [[NSAppleEventDescriptor alloc] initWithAEDesc:anAppleEvent];
516 NSCParameterAssert( self != nil );
518 /* if we have an instance, it has a target and we can create a NSAppleEventDescriptor */
519 if( theSendTarget != nil && theAppleEventDescriptor != nil && (theCurrentProcessOnly == NO || [theAppleEventDescriptor isTargetCurrentProcess]) )
521 theAppleEventDescReply = [theSendTarget sendAppleEvent:theAppleEventDescriptor sendMode:aSendMode sendPriority:aSendPriority timeOutInTicks:aTimeOutInTicks idleProc:anIdleProc filterProc:aFilterProc];
523 if( [theAppleEventDescReply getAEDesc:(AEDesc*)aReply] )
525 theError = noErr; // NO ERROR
528 else if( self->defaultSendProcPtr != NULL )
530 NDLogOSStatus(theError = (self->defaultSendProcPtr)( anAppleEvent, aReply, aSendMode, aSendPriority, aTimeOutInTicks, anIdleProc, aFilterProc, self->defaultSendProcRefCon ));
533 NSLog( @"Failed to send" );
535 [theAppleEventDescriptor release];
541 static OSErr AppleEventSpecialHandler(const AppleEvent * anAppleEvent, AppleEvent * aReply, long aRefCon )
543 NDComponentInstance * self = (id)aRefCon;
544 OSErr theError = errAEEventNotHandled;
545 id theSpecialHandler = [self appleEventSpecialHandler];
546 NSAppleEventDescriptor * theResult = nil;
548 NSCParameterAssert( self != nil );
550 if( theSpecialHandler == nil )
551 theSpecialHandler = self;
553 theResult = [theSpecialHandler handleSpecialAppleEvent:[NSAppleEventDescriptor descriptorWithAEDesc:anAppleEvent]];
556 NSCParameterAssert( [theResult getAEDesc:aReply] );
560 theError = errOSASystemError;
569 * category implementation NDComponentInstance (Private)
571 @implementation NDComponentInstance (Private)
576 - (ComponentInstance)instanceRecord
578 return instanceRecord;